/**
	This is a stub for libWeb.js once it is:
	 - Cleaned up
	 - Formatted
	 - Given a browser testing suite (BB10 ftw)
	The final version will be imported and migration will start.
	 
	This is part of NTUBE-MIGRATION-0004: Migrate base.js into libWeb.
 	Motive for MIGRATION-0004:
 		nTube's base.js has some features like the id() cache which could split into a dedicated library
 		for handling the modern web using vanilla JavaScript.
 		
 		Furthermore, integrating libWeb into nTube would reduce maintainence of base.js as only some minor functions
 		exclusive to nTube's use would remain, while libWeb could be easily updated in between nTube releases.
 		
 	Planned Actions:														Status
 		- Prepare libWeb and make libWeb into an actual library.			70%
 		- Import libWeb														85%
 		- Break nTube by removing parts of base.js							65%
 		- Replace broken components with libWeb calls.						70%
 		
 	Future Action:
 */
/* libWeb: Core Polyfills */
/* Map Polyfill */
if (!window.Map || !Map) {
	/*! (c) Andrea Giammarchi - ISC */
	try {
		self.Map = Map;
	} catch (t) {
		!(function (n, i) {
			"use strict";
			var t = i(s.prototype, {
				size: {
					configurable: !0,
					get: function () {
						return this._k.length;
					},
				},
			});
			return (
				(t.clear = function () {
					var t = this._k.length;
					this._k.splice(0, t), this._v.splice(0, t);
				}),
				(t.delete = function (t) {
					var i = r(this, t);
					return i && (this._k.splice(n, 1), this._v.splice(n, 1)), i;
				}),
				(t.entries = function () {
					return this._k.map(h, this._v);
				}),
				(t.forEach = function (n, s) {
					this._k.forEach(function (t, i) {
						n.call(s, this._v[i], t, this);
					}, this);
				}),
				(t.get = function (t) {
					return r(this, t) ? this._v[n] : void 0;
				}),
				(t.has = function (t) {
					return r(this, t);
				}),
				(t.keys = function () {
					return this._k.slice(0);
				}),
				(t.set = function (t, i) {
					return (this._v[r(this, t) ? n : this._k.push(t) - 1] = i), this;
				}),
				(t.values = function () {
					return this._v.slice(0);
				}),
				(self.Map = s)
			);
			function s(t) {
				i(this, { _k: { value: [] }, _v: { value: [] } }), t && t.forEach(e, this);
			}
			function e(t) {
				this.set(t[0], t[1]);
			}
			function r(t, i) {
				return -1 < (n = t._k.indexOf(i));
			}
			function h(t, i) {
				return [t, this[i]];
			}
		})(0, Object.defineProperties);
	}
}
/* endsWith Polyfill */
if (typeof String.prototype.endsWith !== "function") {
	String.prototype.endsWith = function (suffix) {
		return this.indexOf(suffix, this.length - suffix.length) !== -1;
	};
}
/* libWeb: Required Libraries */
// yallist (modified for libWeb)
Yallist.Node = Node;
Yallist.create = Yallist;

function Yallist(list) {
	var self = this;
	if (!(self instanceof Yallist)) {
		self = new Yallist();
	}

	self.tail = null;
	self.head = null;
	self.length = 0;

	if (list && typeof list.forEach === "function") {
		list.forEach(function (item) {
			self.push(item);
		});
	} else if (arguments.length > 0) {
		for (var i = 0, l = arguments.length; i < l; i++) {
			self.push(arguments[i]);
		}
	}

	return self;
}

Yallist.prototype.removeNode = function (node) {
	if (node.list !== this) {
		throw new Error("removing node which does not belong to this list");
	}

	var next = node.next;
	var prev = node.prev;

	if (next) {
		next.prev = prev;
	}

	if (prev) {
		prev.next = next;
	}

	if (node === this.head) {
		this.head = next;
	}
	if (node === this.tail) {
		this.tail = prev;
	}

	node.list.length--;
	node.next = null;
	node.prev = null;
	node.list = null;

	return next;
};

Yallist.prototype.unshiftNode = function (node) {
	if (node === this.head) {
		return;
	}

	if (node.list) {
		node.list.removeNode(node);
	}

	var head = this.head;
	node.list = this;
	node.next = head;
	if (head) {
		head.prev = node;
	}

	this.head = node;
	if (!this.tail) {
		this.tail = node;
	}
	this.length++;
};

Yallist.prototype.pushNode = function (node) {
	if (node === this.tail) {
		return;
	}

	if (node.list) {
		node.list.removeNode(node);
	}

	var tail = this.tail;
	node.list = this;
	node.prev = tail;
	if (tail) {
		tail.next = node;
	}

	this.tail = node;
	if (!this.head) {
		this.head = node;
	}
	this.length++;
};

Yallist.prototype.push = function () {
	for (var i = 0, l = arguments.length; i < l; i++) {
		push(this, arguments[i]);
	}
	return this.length;
};

Yallist.prototype.unshift = function () {
	for (var i = 0, l = arguments.length; i < l; i++) {
		unshift(this, arguments[i]);
	}
	return this.length;
};

Yallist.prototype.pop = function () {
	if (!this.tail) {
		return undefined;
	}

	var res = this.tail.value;
	this.tail = this.tail.prev;
	if (this.tail) {
		this.tail.next = null;
	} else {
		this.head = null;
	}
	this.length--;
	return res;
};

Yallist.prototype.shift = function () {
	if (!this.head) {
		return undefined;
	}

	var res = this.head.value;
	this.head = this.head.next;
	if (this.head) {
		this.head.prev = null;
	} else {
		this.tail = null;
	}
	this.length--;
	return res;
};

Yallist.prototype.forEach = function (fn, thisp) {
	thisp = thisp || this;
	for (var walker = this.head, i = 0; walker !== null; i++) {
		fn.call(thisp, walker.value, i, this);
		walker = walker.next;
	}
};

Yallist.prototype.forEachReverse = function (fn, thisp) {
	thisp = thisp || this;
	for (var walker = this.tail, i = this.length - 1; walker !== null; i--) {
		fn.call(thisp, walker.value, i, this);
		walker = walker.prev;
	}
};

Yallist.prototype.get = function (n) {
	for (var i = 0, walker = this.head; walker !== null && i < n; i++) {
		// abort out of the list early if we hit a cycle
		walker = walker.next;
	}
	if (i === n && walker !== null) {
		return walker.value;
	}
};

Yallist.prototype.getReverse = function (n) {
	for (var i = 0, walker = this.tail; walker !== null && i < n; i++) {
		// abort out of the list early if we hit a cycle
		walker = walker.prev;
	}
	if (i === n && walker !== null) {
		return walker.value;
	}
};

Yallist.prototype.map = function (fn, thisp) {
	thisp = thisp || this;
	var res = new Yallist();
	for (var walker = this.head; walker !== null; ) {
		res.push(fn.call(thisp, walker.value, this));
		walker = walker.next;
	}
	return res;
};

Yallist.prototype.mapReverse = function (fn, thisp) {
	thisp = thisp || this;
	var res = new Yallist();
	for (var walker = this.tail; walker !== null; ) {
		res.push(fn.call(thisp, walker.value, this));
		walker = walker.prev;
	}
	return res;
};

Yallist.prototype.reduce = function (fn, initial) {
	var acc;
	var walker = this.head;
	if (arguments.length > 1) {
		acc = initial;
	} else if (this.head) {
		walker = this.head.next;
		acc = this.head.value;
	} else {
		throw new TypeError("Reduce of empty list with no initial value");
	}

	for (var i = 0; walker !== null; i++) {
		acc = fn(acc, walker.value, i);
		walker = walker.next;
	}

	return acc;
};

Yallist.prototype.reduceReverse = function (fn, initial) {
	var acc;
	var walker = this.tail;
	if (arguments.length > 1) {
		acc = initial;
	} else if (this.tail) {
		walker = this.tail.prev;
		acc = this.tail.value;
	} else {
		throw new TypeError("Reduce of empty list with no initial value");
	}

	for (var i = this.length - 1; walker !== null; i--) {
		acc = fn(acc, walker.value, i);
		walker = walker.prev;
	}

	return acc;
};

Yallist.prototype.toArray = function () {
	var arr = new Array(this.length);
	for (var i = 0, walker = this.head; walker !== null; i++) {
		arr[i] = walker.value;
		walker = walker.next;
	}
	return arr;
};

Yallist.prototype.toArrayReverse = function () {
	var arr = new Array(this.length);
	for (var i = 0, walker = this.tail; walker !== null; i++) {
		arr[i] = walker.value;
		walker = walker.prev;
	}
	return arr;
};

Yallist.prototype.slice = function (from, to) {
	to = to || this.length;
	if (to < 0) {
		to += this.length;
	}
	from = from || 0;
	if (from < 0) {
		from += this.length;
	}
	var ret = new Yallist();
	if (to < from || to < 0) {
		return ret;
	}
	if (from < 0) {
		from = 0;
	}
	if (to > this.length) {
		to = this.length;
	}
	for (var i = 0, walker = this.head; walker !== null && i < from; i++) {
		walker = walker.next;
	}
	for (; walker !== null && i < to; i++, walker = walker.next) {
		ret.push(walker.value);
	}
	return ret;
};

Yallist.prototype.sliceReverse = function (from, to) {
	to = to || this.length;
	if (to < 0) {
		to += this.length;
	}
	from = from || 0;
	if (from < 0) {
		from += this.length;
	}
	var ret = new Yallist();
	if (to < from || to < 0) {
		return ret;
	}
	if (from < 0) {
		from = 0;
	}
	if (to > this.length) {
		to = this.length;
	}
	for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) {
		walker = walker.prev;
	}
	for (; walker !== null && i > from; i--, walker = walker.prev) {
		ret.push(walker.value);
	}
	return ret;
};

// ...nodes was babel'd due it being an ES6 thing...
Yallist.prototype.splice = function (start, deleteCount) {
	if (start > this.length) {
		start = this.length - 1;
	}
	if (start < 0) {
		start = this.length + start;
	}
	for (var i = 0, walker = this.head; walker !== null && i < start; i++) {
		walker = walker.next;
	}
	var ret = [];
	for (var i = 0; walker && i < deleteCount; i++) {
		ret.push(walker.value);
		walker = this.removeNode(walker);
	}
	if (walker === null) {
		walker = this.tail;
	}
	if (walker !== this.head && walker !== this.tail) {
		walker = walker.prev;
	}
	for (var i = 0; i < (arguments.length <= 2 ? 0 : arguments.length - 2); i++) {
		walker = insert(this, walker, i + 2 < 2 || arguments.length <= i + 2 ? undefined : arguments[i + 2]);
	}
	return ret;
};

Yallist.prototype.reverse = function () {
	var head = this.head;
	var tail = this.tail;
	for (var walker = head; walker !== null; walker = walker.prev) {
		var p = walker.prev;
		walker.prev = walker.next;
		walker.next = p;
	}
	this.head = tail;
	this.tail = head;
	return this;
};

function insert(self, node, value) {
	var inserted = node === self.head ? new YallistNode(value, null, node, self) : new YallistNode(value, node, node.next, self);

	if (inserted.next === null) {
		self.tail = inserted;
	}
	if (inserted.prev === null) {
		self.head = inserted;
	}

	self.length++;

	return inserted;
}

function push(self, item) {
	self.tail = new YallistNode(item, self.tail, null, self);
	if (!self.head) {
		self.head = self.tail;
	}
	self.length++;
}

function unshift(self, item) {
	self.head = new YallistNode(item, null, self.head, self);
	if (!self.tail) {
		self.tail = self.head;
	}
	self.length++;
}

function YallistNode(value, prev, next, list) {
	if (!(this instanceof YallistNode)) {
		return new YallistNode(value, prev, next, list);
	}

	this.list = list;
	this.value = value;

	if (prev) {
		prev.next = this;
		this.prev = prev;
	} else {
		this.prev = null;
	}

	if (next) {
		next.prev = this;
		this.next = next;
	} else {
		this.next = null;
	}
}
// stale-lru-cache (modified for libWeb)
const DoublyLinkedList = Yallist;

function StaleLRU(options) {
	if (!(this instanceof StaleLRU)) {
		return new StaleLRU(options);
	}

	if (typeof options === "number") {
		options = { maxSize: options };
	} else if (!options) {
		options = {};
	}

	this._maxSize = options.max || options.maximumSize || options.maxSize;
	this._getSize = options.length || options.getSize || simpleSize;
	this._maxAge = typeof options.maxAge === "number" ? options.maxAge : Infinity;
	this._staleWhileRevalidate = typeof options.staleWhileRevalidate === "number" ? options.staleWhileRevalidate : 0;
	this._revalidate = options.revalidate;
	this._callbackQueue = new Map(); // Holds revalidate callbacks

	this.reset();
}

StaleLRU.prototype.reset = function () {
	this._lruList = new DoublyLinkedList(); // Holds cache items in order of recent-ness
	this._map = new Map(); // Maps cache keys to LRU list nodes
	this._size = 0;
};

Object.defineProperty(StaleLRU.prototype, "size", {
	get: function () {
		return this._size;
	},
});

Object.defineProperty(StaleLRU.prototype, "maxSize", {
	get: function () {
		return this._maxSize;
	},
});

StaleLRU.prototype.has = function (key) {
	var node = this._map.get(key);
	if (node) {
		var item = node.value;
		return !isPastStale(this, item);
	}
	return false;
};

StaleLRU.prototype.isStale = function (key) {
	var node = this._map.get(key);
	if (node) {
		var item = node.value;
		return isStale(this, item);
	}
	return false;
};

StaleLRU.prototype.get = function (key) {
	var node = this._map.get(key);
	if (node) {
		var item = node.value;
		if (!isPastStale(this, item)) {
			this._lruList.unshiftNode(node);
			if (isStale(this, item)) revalidate(this, item);
			return item.value;
		} else {
			del(this, node);
		}
	}
};

StaleLRU.prototype.set = function (key, value, options) {
	if (typeof options === "string") {
		options = parseCacheControl(options);
	} else if (!options) {
		options = {};
	}
	var now = Date.now();
	var size = this._getSize(value, key);
	var node = this._map.get(key);
	var item;

	if (node) {
		item = node.value;

		// Have it but will not make it in
		if (size > this.maxSize) {
			del(this, node);
			return false;
		}

		// Have it and will make it in
		item.now = now;
		item.maxAge = options.maxAge;
		item.staleWhileRevalidate = options.staleWhileRevalidate;

		if (isPastStale(this, item)) {
			del(this, node);
			return false;
		}

		if (options.revalidate) {
			item.revalidate = options.revalidate;
		}
		item.value = value;
		this._size += size - item.size;
		item.size = size;

		this._lruList.unshiftNode(node);
		trim(this);

		return true;
	}

	// Do not have it and will not make it in
	if (size > this.maxSize) {
		return false;
	}

	// Do not have it but will make it in
	item = new Item(key, value, size, now, options.maxAge, options.staleWhileRevalidate, options.revalidate);

	if (isPastStale(this, item)) {
		return false;
	}

	this._size += size;

	this._lruList.unshift(item);
	this._map.set(key, this._lruList.head);
	trim(this);

	return true;
};

StaleLRU.prototype.delete = function (key) {
	var node = this._map.get(key);
	if (node) {
		del(this, node);
		return true;
	}
	return false;
};

StaleLRU.prototype.keys = function () {
	return this._lruList.toArray().map(function (item) {
		return item.key;
	}, this);
};

StaleLRU.prototype.values = function () {
	return this._lruList.toArray().map(function (item) {
		return item.value;
	}, this);
};

StaleLRU.prototype.wrap = function (key, work, callback) {
	var self = this;
	if (self.has(key)) {
		callback(null, self.get(key));
		return;
	}

	if (self._callbackQueue.has(key)) {
		self._callbackQueue.get(key).push(callback);
		return;
	}
	self._callbackQueue.set(key, [callback]);

	work(key, fulfillQueue);

	function fulfillQueue(error, value, options) {
		if (typeof options === "string") {
			options = parseCacheControl(options);
		} else if (!options) {
			options = {};
		}
		options.revalidate || (options.revalidate = work);
		if (!error) self.set(key, value, options);
		var callbacks = self._callbackQueue.get(key);
		self._callbackQueue.delete(key);
		for (var i = 0; i < callbacks.length; i++) {
			var done = callbacks[i];
			done(error, value);
		}
	}
};

function isStale(self, item) {
	var maxAge = typeof item.maxAge === "number" ? item.maxAge : self._maxAge;
	var staleWhileRevalidate = typeof item.staleWhileRevalidate === "number" ? item.staleWhileRevalidate : self._staleWhileRevalidate;
	var now = Date.now();
	var expires = item.now + maxAge * 1000;
	return expires <= now && now < expires + staleWhileRevalidate * 1000;
}

function isPastStale(self, item) {
	var maxAge = typeof item.maxAge === "number" ? item.maxAge : self._maxAge;
	var staleWhileRevalidate = typeof item.staleWhileRevalidate === "number" ? item.staleWhileRevalidate : self._staleWhileRevalidate;
	return item.now + maxAge * 1000 + staleWhileRevalidate * 1000 <= Date.now();
}

function revalidate(self, item) {
	var key = item.key;
	var work = item.revalidate || self._revalidate;
	if (!work) return;

	if (self._callbackQueue.has(key)) return;
	self._callbackQueue.set(key, []);

	work(key, fulfillQueue);

	function fulfillQueue(error, value, options) {
		if (!error) self.set(key, value, options);
		var callbacks = self._callbackQueue.get(key);
		self._callbackQueue.delete(key);
		for (var i = 0; i < callbacks.length; i++) {
			var done = callbacks[i];
			done(error, value);
		}
	}
}

function trim(self) {
	if (self._size > self._maxSize) {
		for (var node = self._lruList.tail; self._size > self._maxSize && node !== null; ) {
			var prev = node.prev;
			del(self, node);
			node = prev;
		}
	}
}

function del(self, node) {
	var item = node.value;
	self._size -= item.size;
	self._map.delete(item.key);
	self._lruList.removeNode(node);
}

function Item(key, value, size, now, maxAge, staleWhileRevalidate, revalidate) {
	this.key = key;
	this.value = value;
	this.size = size;
	this.now = now;
	this.maxAge = maxAge;
	this.staleWhileRevalidate = staleWhileRevalidate;
	this.revalidate = revalidate;
}

function simpleSize() {
	return 1;
}
// Requires TextDecoder and Uint8Array (Array might work but I don't trust it)
const BASE64_ENABLE_FAST_DECODER = "TextDecoder" in window && "Uint8Array" in window;
// Requires TextEncoder and Uint8Array (Array might work but I don't trust it)
const BASE64_ENABLE_FAST_ENCODER = "TextEncoder" in window && "Uint8Array" in window;
// https://github.com/LinusU/fast-base64-decode (used for BASE64_ENABLE_FAST_DECODER)
var _b64_lookup = [
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 62, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
	9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
];
if ("freeze" in Object) {
	Object.freeze(_b64_lookup);
}
function __base64Decode(source, target) {
	var sourceLength = source.length;
	var paddingLength = source[sourceLength - 2] === "=" ? 2 : source[sourceLength - 1] === "=" ? 1 : 0;

	var tmp;
	var byteIndex = 0;
	var baseLength = (sourceLength - paddingLength) & 0xfffffffc;

	for (var i = 0; i < baseLength; i += 4) {
		tmp = (_b64_lookup[source.charCodeAt(i)] << 18) | (_b64_lookup[source.charCodeAt(i + 1)] << 12) | (_b64_lookup[source.charCodeAt(i + 2)] << 6) | _b64_lookup[source.charCodeAt(i + 3)];

		target[byteIndex++] = (tmp >> 16) & 0xff;
		target[byteIndex++] = (tmp >> 8) & 0xff;
		target[byteIndex++] = tmp & 0xff;
	}

	if (paddingLength === 1) {
		tmp = (_b64_lookup[source.charCodeAt(i)] << 10) | (_b64_lookup[source.charCodeAt(i + 1)] << 4) | (_b64_lookup[source.charCodeAt(i + 2)] >> 2);

		target[byteIndex++] = (tmp >> 8) & 0xff;
		target[byteIndex++] = tmp & 0xff;
	}

	if (paddingLength === 2) {
		tmp = (_b64_lookup[source.charCodeAt(i)] << 2) | (_b64_lookup[source.charCodeAt(i + 1)] >> 4);

		target[byteIndex++] = tmp & 0xff;
	}
}
// https://github.com/beatgammit/base64-js/ (used for BASE64_ENABLE_FAST_DECODER)
var lookup = [];
var revLookup = [];
var Arr = typeof Uint8Array !== "undefined" ? Uint8Array : Array;

var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (var i = 0, len = code.length; i < len; ++i) {
	lookup[i] = code[i];
	revLookup[code.charCodeAt(i)] = i;
}

// Support decoding URL-safe base64 strings, as Node.js does.
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
revLookup["-".charCodeAt(0)] = 62;
revLookup["_".charCodeAt(0)] = 63;

function getLens(b64) {
	var len = b64.length;

	if (len % 4 > 0) {
		throw new Error("Invalid string. Length must be a multiple of 4");
	}

	// Trim off extra bytes after placeholder bytes are found
	// See: https://github.com/beatgammit/base64-js/issues/42
	var validLen = b64.indexOf("=");
	if (validLen === -1) validLen = len;

	var placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4);

	return [validLen, placeHoldersLen];
}

// base64 is 4/3 + up to two characters of the original data
function byteLength(b64) {
	var lens = getLens(b64);
	var validLen = lens[0];
	var placeHoldersLen = lens[1];
	return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;
}

function _byteLength(b64, validLen, placeHoldersLen) {
	return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;
}

function toByteArray(b64) {
	var tmp;
	var lens = getLens(b64);
	var validLen = lens[0];
	var placeHoldersLen = lens[1];

	var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));

	var curByte = 0;

	// if there are placeholders, only get up to the last complete 4 chars
	var len = placeHoldersLen > 0 ? validLen - 4 : validLen;

	var i;
	for (i = 0; i < len; i += 4) {
		tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)];
		arr[curByte++] = (tmp >> 16) & 0xff;
		arr[curByte++] = (tmp >> 8) & 0xff;
		arr[curByte++] = tmp & 0xff;
	}

	if (placeHoldersLen === 2) {
		tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4);
		arr[curByte++] = tmp & 0xff;
	}

	if (placeHoldersLen === 1) {
		tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2);
		arr[curByte++] = (tmp >> 8) & 0xff;
		arr[curByte++] = tmp & 0xff;
	}

	return arr;
}

function tripletToBase64(num) {
	return lookup[(num >> 18) & 0x3f] + lookup[(num >> 12) & 0x3f] + lookup[(num >> 6) & 0x3f] + lookup[num & 0x3f];
}

function encodeChunk(uint8, start, end) {
	var tmp;
	var output = [];
	for (var i = start; i < end; i += 3) {
		tmp = ((uint8[i] << 16) & 0xff0000) + ((uint8[i + 1] << 8) & 0xff00) + (uint8[i + 2] & 0xff);
		output.push(tripletToBase64(tmp));
	}
	return output.join("");
}

function fromByteArray(uint8) {
	var tmp;
	var len = uint8.length;
	var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
	var parts = [];
	var maxChunkLength = 16383; // must be multiple of 3

	// go through the array every three bytes, we'll deal with trailing stuff later
	for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
		parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));
	}

	// pad the end with zeros, but make sure to not forget the extra bytes
	if (extraBytes === 1) {
		tmp = uint8[len - 1];
		parts.push(lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f] + "==");
	} else if (extraBytes === 2) {
		tmp = (uint8[len - 2] << 8) + uint8[len - 1];
		parts.push(lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3f] + lookup[(tmp << 2) & 0x3f] + "=");
	}

	return parts.join("");
}
/* createElement.js */
const LIBWEB_CL_MATCH = "(-?[_a-zA-Z]+[_a-zA-Z0-9-]*)",
	LIBWEB_CL_QUOTE1 = "([\"'])((?:(?=(\\\\?))\\",
	LIBWEB_CL_QUOTE2 = "[\\W\\w])*?)\\",
	LIBWEB_CL_REGEX =
		"^(?:" +
		LIBWEB_CL_MATCH +
		")|^#" +
		LIBWEB_CL_MATCH +
		"|^\\." +
		LIBWEB_CL_MATCH +
		"|^\\[" +
		LIBWEB_CL_MATCH +
		"(?:([*$|~^]?=)" +
		LIBWEB_CL_QUOTE1 +
		"8" +
		LIBWEB_CL_QUOTE2 +
		"6" +
		")?\\]|^\\s*[\\n\\r]+([\\t]*)\\s*|^(\\s+)|^" +
		LIBWEB_CL_QUOTE1 +
		"13" +
		LIBWEB_CL_QUOTE2 +
		"11";
const ORIGINAL_DOCUMENT_CREATE_EL = document.createElement;
function libWeb0_createElement(selectorUntrimmed) {
	"use strict";

	var selector = selectorUntrimmed.replace(/^\s+|\s+$/),
		root = document.createDocumentFragment(),
		nest = [root, ORIGINAL_DOCUMENT_CREATE_EL.call(document, "div")];

	for (var frag = root, node = frag.appendChild(nest[1]), index = 1, first = true, match; selector && (match = selector.match(LIBWEB_CL_REGEX)); ) {
		// tag
		if (match[1]) {
			frag.replaceChild((node = ORIGINAL_DOCUMENT_CREATE_EL.call(document, match[1])), frag.lastChild);

			if (first) nest[index] = node;
		}
		// id
		if (match[2]) node.id = match[2];
		// class
		if (match[3]) node.className += (node.className ? " " : "") + match[3];
		// attribute
		if (match[4]) node.setAttribute(match[4], match[7] || "");
		// nesting
		if (match[9] !== undefined) {
			index = match[9].length;

			frag = nest[index];
			node = nest[++index] = frag.appendChild(ORIGINAL_DOCUMENT_CREATE_EL.call(document, "div"));
		}
		// child
		if (match[10]) {
			frag = node;
			node = frag.appendChild(ORIGINAL_DOCUMENT_CREATE_EL.call(document, "div"));

			first = false;
		}
		// text
		if (match[11]) {
			frag.replaceChild((node = document.createTextNode(match[12])), frag.lastChild);

			if (first) nest[index] = node;
		}

		selector = selector.slice(match[0].length);
	}

	return root.childNodes.length === 1 ? root.lastChild : root;
}
/* libWeb: Polyfills */
// Polyfill for browsers which don't support setTimeout with arguments.
(function setTimeoutModule(global, partial, setInterval, setTimeout, slice) {
	"use strict";
	function polyfiller() {
		if (arguments.length) {
			// no need to polyfill
			return;
		}
		global[setInterval] = partial(global[setInterval], slice);
		global[setTimeout] = partial(global[setTimeout], slice);
	}
	global[setTimeout](polyfiller, 0, global);
})(
	this,
	function setTimeoutPolyfill(method, slice) {
		"use strict";
		return function definition(callback, timeout) {
			var args = slice.call(arguments, 2);
			return method(function application() {
				callback.apply(this, args);
			}, timeout);
		};
	},
	"setInterval",
	"setTimeout",
	Array.prototype.slice
);
// Polyfill for browsers which don't support setImmediate.
(function setImmediateModule(global, slice) {
	"use strict";
	var document, handlers, html, uid;
	if (global.setImmediate) {
		return;
	}
	function clearImmediate(handler) {
		delete handlers[handler];
	}
	function setImmediate() {
		var args = slice.call(arguments),
			handle = "handle_" + uid,
			script = document.createElement("script");
		function onreadystatechange() {
			this.onreadystatechange = null;
			html.removeChild(this);
			if (handlers.hasOwnProperty(handle)) {
				delete handlers[handle];
				args[0].apply(global, args.slice(1));
			}
		}
		uid += 1;
		handlers[handle] = true;
		script.onreadystatechange = onreadystatechange;
		html.appendChild(script); // triggers readystatechange event
		return handle;
	}
	document = global.document;
	handlers = {};
	html = document.documentElement;
	uid = 1;
	global.clearImmediate = clearImmediate;
	global.setImmediate = setImmediate;
})(this, Array.prototype.slice);
// Polyfill for requestAnimationFrame and cancelAnimationFrame
(function requestAnimationFrameModule(global) {
	"use strict";
	var counter,
		hasPerformance = !!(global.performance && global.performance.now),
		lastTime = 0,
		now =
			Date.now ||
			function now() {
				return new Date().getTime();
			},
		rAFOld,
		startTime = now(),
		vendors = ["webkit", "moz"];
	function cancelAnimationFrame(id) {
		global.clearTimeout(id);
	}
	function requestAnimationFrame(callback) {
		var currTime = now(),
			delay = 16 - Math.abs(currTime - lastTime),
			id,
			next = currTime + delay;
		if (delay < 0) {
			delay = 0;
		}
		id = global.setTimeout(function () {
			callback(next);
		}, delay);
		lastTime = next;
		return id;
	}
	counter = vendors.length;
	while (counter && !global.requestAnimationFrame) {
		counter -= 1;
		global.requestAnimationFrame = global[vendors[counter] + "RequestAnimationFrame"];
	}
	if (!global.requestAnimationFrame || /iP(?:[ao]d|hone).*OS 6/.test(global.navigator.userAgent)) {
		global.requestAnimationFrame = requestAnimationFrame;
	} else if (!global.cancelAnimationFrame) {
		global.cancelAnimationFrame = global[vendors[counter] + "CancelAnimationFrame"] || global[vendors[counter] + "CancelRequestAnimationFrame"];
	}
	if (!global.cancelAnimationFrame) {
		global.cancelAnimationFrame = cancelAnimationFrame;
	}
	if (!hasPerformance) {
		rAFOld = global.requestAnimationFrame;
		global.requestAnimationFrame = function (callback) {
			function wrapped(timestamp) {
				var performanceTimestamp = timestamp < 1e12 ? timestamp : timestamp - startTime;
				return callback(performanceTimestamp);
			}
			rAFOld(wrapped);
		};
	}
})(this);
// Polyfill for browsers that lack requestIdleCallback or cancelIdleCallback
if (!window.requestIdleCallback) {
	window.requestIdleCallback = function (callback, options) {
		var options = options || {};
		var relaxation = 1;
		var timeout = options.timeout || relaxation;
		var start = performance.now();
		return setTimeout(function () {
			callback({
				get didTimeout() {
					return options.timeout ? false : performance.now() - start - relaxation > timeout;
				},
				timeRemaining: function () {
					return Math.max(0, relaxation + (performance.now() - start));
				},
			});
		}, relaxation);
	};
}
if (!window.cancelIdleCallback) {
	window.cancelIdleCallback = function (id) {
		clearTimeout(id);
	};
}
// Polyfill for browsers that lack Object.entries
Object.entries = Object.entries
	? Object.entries
	: function (obj) {
			var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"];
			var objType = Object.prototype.toString.call(obj);

			if (obj === null || typeof obj === "undefined") {
				throw new TypeError("Cannot convert undefined or null to object");
			} else if (!~allowedTypes.indexOf(objType)) {
				return [];
			} else {
				// if ES6 is supported
				if (Object.keys) {
					return Object.keys(obj).map(function (key) {
						return [key, obj[key]];
					});
				}
				var result = [];
				for (var prop in obj) {
					if (obj.hasOwnProperty(prop)) {
						result.push([prop, obj[prop]]);
					}
				}

				return objType === "[object Array]"
					? result
					: result.sort(function (a, b) {
							return a[1] - b[1];
					  });
			}
	  };
// Polyfill for browsers that lack Object.values
Object.values = Object.values
	? Object.values
	: function (obj) {
			var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"];
			var objType = Object.prototype.toString.call(obj);

			if (obj === null || typeof obj === "undefined") {
				throw new TypeError("Cannot convert undefined or null to object");
			} else if (!~allowedTypes.indexOf(objType)) {
				return [];
			} else {
				// if ES6 is supported
				if (Object.keys) {
					return Object.keys(obj).map(function (key) {
						return obj[key];
					});
				}

				var result = [];
				for (var prop in obj) {
					if (obj.hasOwnProperty(prop)) {
						result.push(obj[prop]);
					}
				}

				return result;
			}
	  };
// Polyfill for browsers that lack Object.assign
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill
if (typeof Object.assign != "function") {
	Object.assign = function (target, varArgs) {
		// .length of function is 2
		"use strict";
		if (target == null) {
			// TypeError if undefined or null
			throw new TypeError("Cannot convert undefined or null to object");
		}

		var to = Object(target);

		for (var index = 1; index < arguments.length; index++) {
			var nextSource = arguments[index];

			if (nextSource != null) {
				// Skip over if undefined or null
				for (var nextKey in nextSource) {
					// Avoid bugs when hasOwnProperty is shadowed
					if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
						to[nextKey] = nextSource[nextKey];
					}
				}
			}
		}
		return to;
	};
}
// Polyfill for browsers that don't support isInteger (*cough* *cough* BB10)
Number.isInteger =
	Number.isInteger ||
	function (value) {
		return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
	};
// Polyfill for browsers that don't support Array.some()
Array.prototype.some =
	[].some ||
	function (a, b, c, d) {
		for (c = 0, d = this; c < d.length; c++) if (a.call(b, d[c], c, d)) return !0;
		return !1;
	};
// IE console-less fix.
(function () {
	var method;
	var noop = function () {};
	var methods = [
		"assert",
		"clear",
		"count",
		"debug",
		"dir",
		"dirxml",
		"error",
		"exception",
		"group",
		"groupCollapsed",
		"groupEnd",
		"info",
		"log",
		"markTimeline",
		"profile",
		"profileEnd",
		"table",
		"time",
		"timeEnd",
		"timeStamp",
		"trace",
		"warn",
	];
	var length = methods.length;
	var console = (window.console = window.console || {});

	while (length--) {
		method = methods[length];

		// Only stub undefined methods.
		if (!console[method]) {
			console[method] = noop;
		}
	}
})();
// libWeb: async() for functions.
/* libWeb Workaround: Make async function invocation not potentially crash over long periods. */
const LW_USE_SAFE_FUNC_ASYNC = false;
// Setup async function invocation.
Function.prototype.async = function () {
	/**
	 * TODO: Shouldn't we also invoke clearInterval() to prevent potential ID overflow?
	 * This should be investigated, and if so, replace this with:
	 */
	if (LW_USE_SAFE_FUNC_ASYNC) {
		const func_this = this;
		const timer_id = setTimeout
			.bind(
				null,
				function () {
					func_this.apply(null, arguments);
					clearInterval(timer_id);
				},
				0
			)
			.apply(null, arguments);
	} else {
		setTimeout.bind(null, this, 0).apply(null, arguments);
	}
};
// Polyfill for queueMicrotask()
if (typeof window.queueMicrotask !== "function") {
	console.debug("[libWeb.js] Installed polyfill for window.queueMicrotask.");
	window.queueMicrotask = function (callback) {
		if (window.Promise) {
			Promise.resolve()
				.then(callback) // e => setTimeout(() => { throw e; })
				.catch(function (e) {
					setTimeout(function () {
						throw e;
					});
				}); // report exceptions
		} else {
			libWeb.TaskDispatcher.run_promise(callback);
		}
	};
	if (window) {
		window.LIBWEB_HAS_MICROTASK_POLYFILL = true;
	}
	this.LIBWEB_HAS_MICROTASK_POLYFILL = true;
}
// Misc polyfill for integer addition.
Math.iadd = function (a, b) {
	return ((a | 0) + (b | 0)) | 0;
};
// Polyfill for Math.imul
if (!Math.imul) {
	Math.imul = function (x, y) {
		var UINT16 = 0xffff;
		var xn = +x;
		var yn = +y;
		var xl = UINT16 & xn;
		var yl = UINT16 & yn;
		return 0 | (xl * yl + ((((UINT16 & (xn >>> 16)) * yl + xl * (UINT16 & (yn >>> 16))) << 16) >>> 0));
	};
}
/* libWeb: Main Source Code */
const libWeb = {};
libWeb.version = "19-09-2022";
libWeb.abiId = 1;
libWeb.COOKIE_MAX_LENGTH = 9007199254740991;
/* libWeb: Modules */
libWeb.ESCompat = {
	checkIfCompatible: function (esVersion) {
		switch (esVersion) {
			/* ES10/2019 */
			case 2019:
			case "10.0":
			case 10:
			case 10.0:
				return "flat" in Array.prototype && "flatMap" in Array.prototype;
			/* ES9/2018 */
			case 2018:
			case "9.0":
			case 9:
			case 9.0:
				return Promise && "finally" in Promise.prototype;
			/* ES8/2017 */
			case 2017:
			case "8.0":
			case 8:
			case 8.0:
				return "values" in Object && "entries" in Object && "getOwnPropertyDescriptors" in Object;
			/* ES7/2016 */
			case 2016:
			case "7.0":
			case 7:
			case 7.0:
				return "includes" in Array.prototype;
			/* ES6 (ES2015) */
			case 2015:
			case "6.0":
			case 6:
			case 6.0: {
				try {
					Function("() => {};");
					return true;
				} catch (exception) {
					return false;
				}
			}
			/* ES5 */
			case "5.0":
			case 5:
			case 5.0:
				return "create" in Object && "isArray" in Array && "x"[0] === "x";
			/* ES4 */
			case "4.0":
			case 4:
			case 4.0:
				return false; // Doesn't exist
			/* ES3 */
			case "3.0":
			case 3:
			case 3.0:
			/* ES2 */
			case "2.0":
			case 2:
			case 2.0:
			/* JavaScript 1.x */
			case "1.0":
			case 1:
			case 1.0:
				return true; // How would you be running this lol
			default:
				console.warn("Unknown ES version: ", esVersion);
				return false;
		}
	},
};
libWeb.BrowserEnvironment = {
	isIE11: !!window.MSInputMethodContext && !!document.documentMode,
	ieVersion: (function () {
		if (window.ActiveXObject === undefined) return null; //Not IE
		if (!window.XMLHttpRequest) return 6;
		if (!document.querySelector) return 7;
		if (!document.addEventListener) return 8;
		if (!window.atob) return 9;
		if (!document.__proto__) return 10;
		return 11;
	})(),
	isMobileWebKit: function () {
		var iDevices = ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"];

		if (!!navigator.platform) {
			while (iDevices.length) {
				if (navigator.platform === iDevices.pop()) {
					return true;
				}
			}
		}
		return false;
	},
	getBrowserVersion: function () {
		if (navigator.userAgentData) {
			const browser_brands = navigator.userAgentData.brands;
			if (browser_brands !== null && browser_brands !== undefined && browser_brands.length > 0) {
				var browser_info_obj;
				for (var i = 0; i < browser_brands.length; i++) {
					const brand = browser_brands[i];
					if (brand === null || brand === undefined || !brand["brand"]) continue;
					if (brand["brand"] && (brand["brand"].contains("Not A") || brand["brand"].contains("Brand"))) continue;
					browser_info_obj = brand;
					break;
				}
				if (browser_info_obj !== null && browser_info_obj !== undefined && browser_info_obj["version"]) {
					try {
						var true_brand = browser_info_obj["brand"];
						if (true_brand === "Chromium") {
							true_brand = "Chrome";
						}
						return true_brand + " " + parseInt(browser_info_obj["version"]);
					} catch (ex) {
						console.error("Failed to get hints, falling back...", ex);
					}
				}
			}
		}
		var ua = navigator.userAgent,
			tem,
			M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
		if (/trident/i.test(M[1])) {
			tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
			return "IE " + (tem[1] || "");
		}
		if (M[1] === "Chrome") {
			tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
			if (tem != null) return tem.slice(1).join(" ").replace("OPR", "Opera");
		}
		M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, "-?"];
		if ((tem = ua.match(/version\/(\d+)/i)) != null) M.splice(1, 1, tem[1]);
		return M.join(" ");
	},
	isChromeFunc: function () {
		try {
			return (typeof window.chrome === "object" || typeof window.chrome.runtime === "object" || typeof window.chrome.csi === "function") && typeof InstallTrigger !== "object";
		} catch (e) {
			return false;
		}
	},
	isOpera: (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(" OPR/") >= 0,
	isFirefox: typeof InstallTrigger !== "undefined",
	isSafari:
		/constructor/i.test(window.HTMLElement) ||
		(function (p) {
			return p.toString() === "[object SafariRemoteNotification]";
		})(!window["safari"] || (typeof safari !== "undefined" && safari.pushNotification)),
	isIE: false || !!document.documentMode,
	isEdge: !this.isIE && !!window.StyleMedia,
	isChrome: (function () {
		try {
			return (typeof window.chrome === "object" || typeof window.chrome.runtime === "object" || typeof window.chrome.csi === "function") && typeof InstallTrigger !== "object";
		} catch (e) {
			return false;
		}
	})(),
	isChromeOS: /(CrOS)/.test(navigator.userAgent),
	isBlink: (this.isChrome || this.isOpera) && !!window.CSS,
};
libWeb.TaskDispatcher = {
	TaskPriority: {
		MICROTASK: -1, // only available if supported by environment
		BACKGROUND_TASK: 0, // default
		VISIBLE_TASK: 1, // default by postTask()
		BLOCKING_TASK: 2,
		ASYNC_TASK: 3,
	},
	supportsMicrotasks: function () {
		return typeof window.queueMicrotask === "function" && !window.LIBWEB_HAS_MICROTASK_POLYFILL;
	},
	usingAsyncMicrotasks: function () {
		return this.supportsMicrotasks() && !(window.scheduler && window.scheduler.postTask) && window.setTimeout;
	},
	run_task: function (func, promisePriority) {
		if (!Number.isInteger(promisePriority)) throw new Error("run_task: Illegal priority: " + promisePriority);
		if (promisePriority < -1 || promisePriority > 3) throw new Error("run_task: Illegal promise priority!");
		try {
			if (promisePriority === 3) {
				if (typeof window.queueMicrotask === "function") {
					window.queueMicrotask(function () {
						func.async();
					});
				} else {
					libWeb.TaskDispatcher.run_task(function () {
						func.async();
					}, libWeb.TaskDispatcher.TaskPriority.BACKGROUND_TASK);
				}
			} else if (promisePriority === -1 && typeof window.queueMicrotask === "function") {
				window.queueMicrotask(func);
			} else if (window.scheduler && window.scheduler.postTask) {
				var pri = null;
				if (promisePriority === 0) {
					pri = "background";
				} else if (promisePriority === 1) {
					pri = "user-visible";
				} else if (promisePriority === 2) {
					pri = "user-blocking";
				} else {
					pri = "background";
				}
				if (pri === null) throw new Error("run_task: Failed to convert task priority!");
				return window.scheduler.postTask(func, { priority: pri }).result;
			} else if (window.Promise) {
				if (typeof PromiseQueuePlus !== "undefined" && window.promise_queue) {
					if (promisePriority >= 1 && promisePriority != 3) return window.promise_queue.push(func);
					return window.promise_queue.unshift(func);
				} else {
					return new window.Promise(func);
				}
			} else {
				return (function () {
					var n = func();
					return {
						value: n,
						then: function (y) {
							y(n);
						},
					};
				})();
			}
		} catch (e) {
			console.error(e);
		}
	},
	run_promise: function (func) {
		libWeb.TaskDispatcher.run_task(func, libWeb.TaskDispatcher.TaskPriority.BACKGROUND_TASK);
	},
	run_async: function (func) {
		if (libWeb.TaskDispatcher.usingAsyncMicrotasks()) {
			libWeb.TaskDispatcher.run_task(func, libWeb.TaskDispatcher.TaskPriority.ASYNC_TASK);
		} else {
			libWeb.TaskDispatcher.run_task(func, libWeb.TaskDispatcher.TaskPriority.BACKGROUND_TASK);
		}
	},
};
libWeb.Math = {
	average: function () {
		if (arguments.length == 0) {
			return 0;
		} else {
			if (arguments.length == 1 && Array.isArray(arguments[0])) {
				var n = 0;
				for (var i = 0; i < arguments[0].length; i++) {
					n += arguments[0][i];
				}
				return n / arguments[0].length;
			} else {
				var n = 0;
				for (var i = 0; i < arguments.length; i++) {
					n += arguments[i];
				}
				return n / arguments.length;
			}
		}
	},
};
libWeb.Requests = {
	USE_PROMISED_REQUESTS: false,
	__apply_request_header_as_required: function (XHR, hasData, headers, data) {
		if (!hasData) return;

		if (
			headers !== null &&
			headers !== undefined &&
			Object.keys(headers).some(function (item) {
				return item.toLowerCase() == "content-type";
			})
		) {
			return;
		}

		if (typeof data === "object") {
			XHR.setRequestHeader("Content-type", "application/json;charset=UTF-8");
		}
	},
	getXHRObject: function () {
		try {
			return new XMLHttpRequest();
		} catch (e) {}
		try {
			return new ActiveXObject("Msxml3.XMLHTTP");
		} catch (e) {}
		try {
			return new ActiveXObject("Msxml2.XMLHTTP.6.0");
		} catch (e) {}
		try {
			return new ActiveXObject("Msxml2.XMLHTTP.3.0");
		} catch (e) {}
		try {
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {}
		try {
			return new ActiveXObject("Microsoft.XMLHTTP");
		} catch (e) {}
		return null;
	},
	hasRequestData: function (params) {
		return params !== null && typeof params !== "function";
	},
	request: function () {
		var url = null;
		var params = null;
		var fail = null;
		var success = null;
		var headers = {};
		const args = arguments;
		for (var i = 0; i < args.length; i++) {
			const arg = args[i];
			if (arg === null || arg === undefined) continue;
			if (typeof arg === "string" && url === null) {
				url = arg;
				continue;
			} else if (typeof arg === "string" && params === null) {
				params = arg;
				continue;
			} else if (typeof arg === "function" && fail === null) {
				fail = arg;
				continue;
			} else if (typeof arg === "function" && success === null) {
				success = arg;
				continue;
			} else if (typeof arg === "object") {
				headers = arg;
				continue;
			} else {
				console.warn("[libWeb::request] Unknown arg: " + arg);
			}
		}
		if (fail === null) {
			// TODO: Decide if this should be kept.
			fail = function (error) {
				console.error(error);
			};
		}
		if (url === null || fail === null || success === null) throw new Error("Arguments missing!");
		const __supports_fetch = typeof fetch != "undefined" && !libWeb.BrowserEnvironment.isMobileWebKit();
		function do_promise() {
			if (__supports_fetch) {
				(libWeb.Requests.hasRequestData(params)
					? fetch(url, {
							method: "POST",
							body: params,
							headers: headers,
					  })
					: fetch(url, {
							headers: headers,
					  })
				)
					.then(function (response) {
						return response.text();
					})
					.then(function (data) {
						success(data);
					})
					.catch(function (ex) {
						fail(ex);
					});
			} else {
				try {
					var XHR = libWeb.Requests.getXHRObject();
					if (XHR == null) {
						throw Error("[libWeb::request] Failed to acquire an XHR object. Is your browser older than IE 8?");
					}
					const __hasData0 = libWeb.Requests.hasRequestData(params);
					XHR.open(__hasData0 ? "POST" : "GET", url, true);
					libWeb.Requests.__apply_request_header_as_required(XHR, __hasData0, headers, params);
					if (headers !== null && headers !== undefined && headers.length > 0) {
						const XHR_ENTRIES_0 = Object.entries(headers);
						XHR_ENTRIES_0.forEach(function (_entry) {
							XHR.setRequestHeader(_entry[0], _entry[1]);
						});
					}
					XHR.onreadystatechange = function () {
						if (XHR.readyState == 4) {
							var sp = XHR.responseText.split("\n");
							success(sp[sp.length - 1]);
						}
					};
					if (__hasData0) {
						XHR.send(params);
					} else {
						XHR.send();
					}
				} catch (e) {
					fail(e);
				}
			}
		}
		if (this.USE_PROMISED_REQUESTS && !__supports_fetch) {
			libWeb.TaskDispatcher.run_promise(do_promise);
		} else {
			do_promise();
		}
	},
	requestWithProgress: function () {
		var url = null;
		var params = null;
		var fail = null;
		var success = null;
		var headers = {};
		var progressCallback = null;
		const args = arguments;
		for (var i = 0; i < args.length; i++) {
			const arg = args[i];
			if (arg === null || arg === undefined) continue;
			if (typeof arg === "string" && url === null) {
				url = arg;
				continue;
			} else if (typeof arg === "string" && params === null) {
				params = arg;
				continue;
			} else if (typeof arg === "function" && fail === null) {
				fail = arg;
				continue;
			} else if (typeof arg === "function" && success === null) {
				success = arg;
				continue;
			} else if (typeof arg === "function" && progressCallback === null) {
				progressCallback = arg;
				continue;
			} else if (typeof arg === "object") {
				headers = arg;
				continue;
			} else {
				console.warn("[libWeb::request] Unknown arg: " + arg);
			}
		}
		if (fail === null) {
			// TODO: Decide if this should be kept.
			fail = function (error) {
				console.error(error);
			};
		}
		if (url === null || fail === null || success === null) throw new Error("Arguments missing!");
		const __supports_fetch2 = typeof fetch != "undefined" && !libWeb.Environment.isMobileWebKit();
		function do_promise() {
			if (__supports_fetch2) {
				(params != null && typeof params !== "function"
					? fetch(url, {
							method: "POST",
							body: params,
							headers: headers,
							cache: "only-if-cached",
					  })
					: fetch(url, {
							cache: "only-if-cached",
							headers: headers,
					  })
				)
					.then(function (response) {
						return response.text();
					})
					.then(function (data) {
						success(data);
					})
					.catch(function (ex) {
						fail(ex);
					});
			} else {
				try {
					var XHR = libWeb.Requests.getXHRObject();
					if (XHR == null) {
						throw Error("[libWeb::request] Failed to acquire an XHR object. Is your browser older than IE 8?");
					}
					const __hasData1 = libWeb.Requests.hasRequestData(params);
					XHR.open(__hasData1 ? "POST" : "GET", url, true);
					libWeb.Requests.__apply_request_header_as_required(XHR, __hasData1, headers, params);
					if (headers !== null && headers !== undefined && headers.length > 0) {
						const XHR_ENTRIES_1 = Object.entries(headers);
						XHR_ENTRIES_1.forEach(function (_entry) {
							XHR.setRequestHeader(_entry[0], _entry[1]);
						});
					}
					if (progressCallback !== null) {
						XHR.onprogress = function (evt) {
							if (evt.lengthComputable) {
								progressCallback({ type: "progress", value: (evt.loaded / evt.total) * 100 });
							}
						};
					}
					XHR.onreadystatechange = function () {
						if (XHR.readyState == 4) {
							var sp = XHR.responseText.split("\n");
							success(sp[sp.length - 1]);
						}
					};
					if (__hasData1) {
						XHR.send(params);
					} else {
						XHR.send();
					}
				} catch (e) {
					fail(e);
				}
			}
		}
		if (this.USE_PROMISED_REQUESTS && !__supports_fetch2) {
			libWeb.TaskDispatcher.run_task(do_promise, libWeb.TaskDispatcher.TaskPriority.VISIBLE_TASK);
		} else {
			do_promise();
		}
	},
};
libWeb.Media = {
	supportsVideoType: function (type) {
		var video;
		const formats = {
			ogg: 'video/ogg; codecs="theora"',
			h264: 'video/mp4; codecs="avc1.42E01E"',
			webm: 'video/webm; codecs="vp8, vorbis"',
			vp9: 'video/webm; codecs="vp9"',
			hls: 'application/x-mpegURL; codecs="avc1.42E01E"',
			av1: 'video/mp4; codecs="av01.0.04M.08"',
			av1_webm: 'video/webm; codecs="av01.0.04M.08"',
			hevc: 'video/mp4; codecs="hev1.1.6.L93.B0"',
		};
		if (!video) {
			video = document.createElement("video");
		}
		if (window.MediaSource && window.MediaSource.isTypeSupported) {
			if (MediaSource.isTypeSupported(formats[type] || type)) return "probably";
			return "";
		} else {
			if (!video.canPlayType) {
				console.warn("[libWeb::supportsVideoType] video.canPlayType is missing! [fail at: " + type + "]");
				return "";
			}
			return video.canPlayType(formats[type] || type);
		}
	},
};
libWeb.Codec = {};
libWeb.Codec.Base64 = {
	decode: function (str) {
		try {
			if (BASE64_ENABLE_FAST_DECODER) {
				/// XXX: libWeb-EXPERIMENT-001: Faster Base64 decoding.
				const __len = byteLength(str);
				const __data = window.Uint8Array ? new Uint8Array(__len) : new Array(__len);
				__base64Decode(str, __data);
				return new TextDecoder().decode(__data);
			} else {
				return decodeURIComponent(
					Array.prototype.map
						.call(atob(str), function (c) {
							return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
						})
						.join("")
				);
			}
		} catch (ex) {
			return atob(str);
		}
	},
	encode: function (str) {
		try {
			if (BASE64_ENABLE_FAST_ENCODER) {
				/// XXX: libWeb-EXPERIMENT-001: Faster Base64 encoding.
				const __arr = new TextEncoder().encode(str);
				return fromByteArray(__arr);
			} else {
				return btoa(
					encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
						return String.fromCharCode(parseInt(p1, 16));
					})
				);
			}
		} catch (ex) {
			return btoa(str);
		}
	},
};
libWeb.Cookies = {
	setCookie: function (name, value, days) {
		var expires = "";
		if (days) {
			var date = new Date();
			date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
			expires = "; expires=" + date.toUTCString();
		}
		var val = value;
		if (value == null) {
			val = "null";
		} else if (typeof value != "string") {
			val = value.toString();
		}
		document.cookie = name + "=" + (val || "") + expires + "; SameSite=Lax; path=/";
	},
	getCookie: function (name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(";");
		for (var i = 0; i < ca.length; i++) {
			var c = ca[i];
			while (c.charAt(0) == " ") c = c.substring(1, c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
		}
		return null;
	},
	eraseCookie: function (name) {
		document.cookie = name + "=; Max-Age=-99999999;";
	},
	canStoreData: function () {
		return typeof Storage === "function" || typeof Storage === "object" || navigator.cookieEnabled;
	},
};
libWeb.Time = {
	timeSince: function (date) {
		var seconds = Math.floor((new Date() - date) / 1000);
		var interval = seconds / 31536000;
		if (interval > 1) {
			return Math.floor(interval) + " years";
		}
		interval = seconds / 2592000;
		if (interval > 1) {
			return Math.floor(interval) + " months";
		}
		interval = seconds / 86400;
		if (interval > 1) {
			return Math.floor(interval) + " days";
		}
		interval = seconds / 3600;
		if (interval > 1) {
			return Math.floor(interval) + " hours";
		}
		interval = seconds / 60;
		if (interval > 1) {
			return Math.floor(interval) + " minutes";
		}
		return Math.floor(seconds) + " seconds";
	},
};
libWeb.runIsolated = function (code) {
	const __tmpObj = {};
	const __tmpFunc = new Function("self", "window", "'use strict';" + code);
	__tmpFunc.call(__tmpObj, __tmpObj, __tmpObj);
};
const id_cache = new StaleLRU({
	maxSize: 100,
	maxAge: 60,
});
libWeb.IdCache = {
	id: function (e) {
		const r = id_cache.get(e);
		if (r == null) {
			const _r = document.getElementById(e);
			if (_r === null || _r === undefined) return _r;
			id_cache.set(e, _r);
			return _r;
		} else {
			return r;
		}
	},
};
libWeb.Notifications = {
	isSupported: function () {
		return window.Notification || window.mozNotification || window.webkitNotification;
	},
	hasPermission: function () {
		var Notification = window.Notification || window.mozNotification || window.webkitNotification;
		return Notification["permission"] === "granted";
	},
	requestPermission: function (success, failure) {
		if (window.Notification) {
			return window.Notification.requestPermission().then(success).catch(failure);
		} else {
			var Notification = window.Notification || window.mozNotification || window.webkitNotification;
			Notification.requestPermission(function (permission) {
				if (permission === "granted") {
					success(permission);
				} else {
					failure(permission);
				}
			});
		}
	},
	sendNotification: function () {},
};
libWeb.DOM = {
	create_dom: function (name) {
		const el = libWeb0_createElement(name);
		const wrap = {
			make: function () {
				return el;
			},
			appendTo: function (element) {
				if (!(element instanceof HTMLElement)) {
					throw new Error("element is not instance of HTMLElement!");
				} else {
					element.appendChild(el);
				}
			},
			text: function (str) {
				el.innerText = str;
				return wrap;
			},
			html: function (str) {
				el.innerHTML = str;
				return wrap;
			},
			attribute: function (key, value) {
				el.setAttribute(key, value);
				return wrap;
			},
			style: function (obj) {
				if (Array.isArray(obj)) {
				} else {
					Object.entries(obj).forEach(function (arr) {
						if (arr === null || arr === undefined || arr.length != 2) {
							return;
						} else {
							el.style[arr[0]] = arr[1];
						}
					});
				}
				// XXX: support [{color: "red"}]
				return wrap;
			},
		};
		return wrap;
	},
	createElement: function (selectorUntrimmed) {
		return libWeb0_createElement(selectorUntrimmed);
	},
};
/* */
if ("freeze" in Object) {
	Object.freeze(libWeb);
}
/* libWeb: nTube Compat */
window.web = libWeb;
window.run_task = libWeb["TaskDispatcher"]["run_task"];
window.run_async = libWeb["TaskDispatcher"]["run_async"];
window.run_promise = libWeb["TaskDispatcher"]["run_promise"];
window.request = libWeb["Requests"]["request"];
window.isIE11 = libWeb["BrowserEnvironment"]["isIE11"];
window.isMobileWebKit = libWeb["BrowserEnvironment"]["isMobileWebKit"];
window.ie = libWeb["BrowserEnvironment"]["ieVersion"];
window.is_iPhoneOS = window.isMobileWebKit;
window.getBrowserVersion = libWeb["BrowserEnvironment"]["getBrowserVersion"];
window.average = libWeb["Math"]["average"];
window.setCookie = libWeb["Cookies"]["setCookie"];
window.getCookie = libWeb["Cookies"]["getCookie"];
window.eraseCookie = libWeb["Cookies"]["eraseCookie"];
window.canStoreData = libWeb["Cookies"]["canStoreData"];
window.base64Decode = libWeb["Codec"]["Base64"]["decode"];
window.base64Encode = libWeb["Codec"]["Base64"]["encode"];
const id = libWeb["IdCache"]["id"];
window.id = id;
Math.average = libWeb["Math"]["average"];
